package org.yeasy.common.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * The type Cud bean util.cud的bean工具
 *
 * @author yangyishe
 * @date 2022年09月22日 14:05
 */
public class CommonBeanUtil {

    /**
     * New instance t.
     *
     * @param <T>   the type parameter
     * @param clazz the clazz
     * @return the t
     * @author yangyishe
     * @date 2022年09月14日 14:36
     */
    public static <T extends Serializable> T newInstance(Class<T> clazz) {
        if (clazz == JSONObject.class) {
            return (T) ReflectUtil.newInstance(JSONObject.class);
        } else {
            return ReflectUtil.newInstance(clazz);
        }
    }

    /**
     * Calc getter name string.
     *
     * @param field the field
     * @return the string
     * @author yangyishe
     * @date 2022年08月31日 14:55
     */
    public static String calcGetterName(String field){
        return "get"+field.substring(0,1).toUpperCase()+field.substring(1);
    }

    /**
     * Calc setter name string.
     *
     * @param field the field
     * @return the string
     * @author yangyishe
     * @date 2022年08月31日 14:55
     */
    public static String calcSetterName(String field) {
        return "set"+field.substring(0,1).toUpperCase()+field.substring(1);
    }

    /**
     * Invoke getter u.
     *
     * @param <T>   the type parameter
     * @param <U>   the type parameter
     * @param obj   the obj
     * @param field the field
     * @return the u
     * @author yangyishe
     * @date 2022年08月31日 14:55
     */
    public static<T,U> U invokeGetter(T obj, String field){
        if(StrUtil.isEmpty(field)){
            throw new RuntimeException("Field can't be empty.");
        }
        boolean isJson=obj.getClass()== JSONObject.class;
        if(isJson){
            return ReflectUtil.invoke(obj,"get",field);
        }else{
            return ReflectUtil.invoke(obj,calcGetterName(field));
        }
    }

    /**
     * Invoke setter.
     *
     * @param <T>   the type parameter
     * @param <U>   the type parameter
     * @param obj   the obj
     * @param field the field
     * @param val   the val
     * @author yangyishe
     * @date 2022年08月31日 14:55
     */
    public static<T,U> void invokeSetter(T obj,String field,U val){
        if(StrUtil.isEmpty(field)){
            throw new RuntimeException("Field can't be empty.");
        }
//        if(val==null){
//            throw new RuntimeException("ReportBeanUtil invoke setter param can't be null.");
//        }
        boolean isJson=obj.getClass()== JSONObject.class;
        if(isJson){
            ReflectUtil.invoke(obj,"put",field,val);
        }else{
            String setterName = calcSetterName(field);
            Method[] methods = obj.getClass().getMethods();
            List<Method> setterList = Arrays.stream(methods).filter(item -> item.getName().equals(setterName)).collect(Collectors.toList());
            if(setterList.size()!=1){
                throw new RuntimeException("not found setter :"+setterName);
            }
            if(val==null){
                Method method = setterList.get(0);
                ReflectUtil.invoke(obj,method,new Object[]{null});
            }else{
                // 先判断有无类型完全匹配的set方法, 有则优先用, 没有再考虑转换
                for (Method method : setterList) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if(parameterTypes.length!=1){
                        throw new IllegalArgumentException("setter argument type length must be one!"+setterName);
                    }
                    Class<?> parameterType = parameterTypes[0];
                    if(parameterType ==val.getClass()){
                        ReflectUtil.invoke(obj,method,val);
                        break;
                    }
                    // 如果确实没有想要转换的类型, 再考虑注册转换器
                    Object convertVal = Convert.convert(parameterType, val);
                    ReflectUtil.invoke(obj,method,convertVal);
                }
            }
        }
    }

    /**
     * Bean 2 json batch list.
     *
     * @param <T>      the type parameter
     * @param beanList the bean list
     * @return the list
     * @author yangyishe
     * @date 2022年08月31日 14:55
     */
    public static <T> List<JSONObject> bean2JsonBatch(List<T> beanList) {
        return beanList.stream().map(o -> (JSONObject) JSON.toJSON(o)).collect(Collectors.toList());
    }

    /**
     * Json 2 bean batch list.
     *
     * @param <T>      the type parameter
     * @param jsonList the json list
     * @param clazz    the clazz
     * @return the list
     * @author yangyishe
     * @date 2022年08月31日 14:55
     */
    public static <T> List<T> json2BeanBatch(List<JSONObject> jsonList, Class<T> clazz) {
        return jsonList.stream().map(o -> o.toJavaObject(clazz)).collect(Collectors.toList());
    }

    /**
     * Calc 2 all field name set.计算所有的域名称
     *
     * @param <T> the type parameter
     * @param obj the obj
     * @return the set
     * @author yangyishe
     * @date 2022年09月07日 15:50
     */
    public static <T extends Serializable> Set<String> calc2AllFieldName(T obj) {
        boolean isJson = obj.getClass() == JSONObject.class;
        if (isJson) {
            return ((JSONObject) obj).keySet();
        } else {
            return Arrays.stream(obj.getClass().getDeclaredFields()).map(Field::getName).collect(Collectors.toSet());
        }
    }

}
